-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix for issue #505 (Better error message for missing keyword argument) #512
Conversation
Looks good to me. You could consider distinguishing between one or more missing arguments (argument vs arguments). I think most other error messages do this. |
@spkersten, sounds good to me, I somewhat expected that the format of the message would be discussed in the pull request. :) @JukkaL, how do you feel about splitting the error message (argument vs arguments)? |
@ivuk Thanks! Looks pretty good -- but I see a few issues. First, I agree with @spkersten -- it would be better to have a separate messages for 1 and 2+ arguments. Another thing that actually makes this a bit tricky: Python has some built-in functions that don't accept keyword arguments, such as >>> ord()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: ord() takes exactly one argument (0 given)
>>> def my_ord(c): pass
...
>>> my_ord()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: my_ord() missing 1 required positional argument: 'c' However, mypy (at least currently) does not distinguish between With the above refinement the only confusing case is when some code tries to call a built-in function with keyword arguments, even though it shouldn't be valid. I added a new issue to address this issue: #516. You don't need to worry about #516, though. |
OK, I hope I got it right. The test cases I used now look like this: def a(x, y): pass
a(x=1)
def b(x, y): pass
b(y=1)
def c(x, y, z): pass
c(x=1)
def d(x, y, z): pass
d(y=1)
def e(x, y, z): pass
e(z=1)
def f(x): pass
f()
def g(x, y): pass
g()
def h(x, y, z): pass
h() And the output is this: $ mypy test.py
test.py, line 4: Missing positional argument "y" in call to "a"
test.py, line 7: Missing positional argument "x" in call to "b"
test.py, line 10: Missing positional arguments "y", "z" in call to "c"
test.py, line 13: Missing positional arguments "x", "z" in call to "d"
test.py, line 16: Missing positional arguments "x", "y" in call to "e"
test.py, line 19: Too few arguments for "f"
test.py, line 22: Too few arguments for "g"
test.py, line 25: Too few arguments for "h" |
Looks good! |
@JukkaL, great! :) What's the next step, should I update the failing test cases? |
Yes, you should update the failing test cases and potentially add some new test cases if they don't cover all the interesting cases. You can try running |
One more point: if you use the automatic test case update feature, review the changes and make sure they are okay before committing. I'm not sure how reliable it is :) |
It's just a handful of them, so no worries there. :) I've came across a test I'm unsure about, it's in [case testCallingWithTupleVarArgs]
from typing import Undefined
a = Undefined # type: A
b = Undefined # type: B
c = Undefined # type: C
cc = Undefined # type: CC
f(*(a, b, b)) # E: Argument 1 to "f" has incompatible type "Tuple[A, B, B]"; expected "A"
f(*(b, b, c)) # E: Argument 1 to "f" has incompatible type "Tuple[B, B, C]"; expected "A"
f(a, *(b, b)) # E: Argument 2 to "f" has incompatible type "Tuple[B, B]"; expected "B"
f(b, *(b, c)) # E: Argument 1 to "f" has incompatible type "B"; expected "A"
f(*(a, b)) # E: Too few arguments for "f"
f(*(a, b, c, c)) # E: Too many arguments for "f"
f(a, *(b, c, c)) # E: Too many arguments for "f"
f(*(a, b, c))
f(a, *(b, c))
f(a, b, *(c,))
f(a, *(b, cc))
def f(a: 'A', b: 'B', c: 'C') -> None: pass
class A: pass
class B: pass
class C: pass
class CC(C): pass
[builtins fixtures/tuple.py] With the new syntax, the output for 'Too few arguments for "f"' ends up as:
I'm not really sure that's correct in this situation, so I figured I'd get a second opinion. :) How do you feel about this? From what I can tell (by using the |
Might be an existing bug. The |
Yeah, looks like an existing bug. It's okay to have the new output and give argument names for now in this special case. Maybe you could you file an issue for this so that it can be sorted out later, and also mention the |
Running |
I think that is failing when is performed the static analysis to the mypy code. Actually, in mypy/messages.py, lines 407 and 408, when you try to get the attribute "arg_names" from Context type, that don't have it. |
@rockneurotiko is right. You could solve this by giving You might also consider renaming the Btw, I noticed that the |
@spkersten thanks for the taking the time to explain this, I really appreciate it! I did a quick hack to try out your proposition with passing in @JukkaL, if you agree, I'd like to implement this the way @spkersten suggested, it's not complicated. As far as the |
730b4ae implements what @spkersten suggested, now the tests are failing because of the |
I've removed the @JukkaL, is this an acceptable solution? I don't see any downside to it, but I could be missing something. |
@ivuk, you're welcome. |
Hmm, it looks mostly good, but this test case (in
Why does it complain about two missing positional arguments? |
For this particular test case, The check I'm using, If I were to extend the test to something like |
That sounds like a reasonable approach. We may be able to relax the condition and give argument names in more messages once we've addressed #516. |
Last few commits implement the aforementioned solution and revert most of the test cases to the "old" output, seems OK to me. :) |
Looks good now! |
Fix for issue #505 (Better error message for missing keyword argument)
Hi, would something like this be acceptable as a fix for issue #505?
This is what I tested with:
And these are the results:
I haven't updated the test cases that rely on the current output, so 20 or so tests are failing at the moment, I can update those as well if this is acceptable.